﻿/**************************************************************

项目名称 :ThinkWide数据访问基础库
版权所有 (c) 2009 ThinkWide
+-------------------------------------------------------------
项目: 


版本: 1


创建日期:2009-5-3


作者: 章称

+-------------------------------------------------------------
描述:z

更新:   2009-5-3
        2010-7 添加View 支持
 *      2010-7 添加SQLUpdate 支持
 *      2010-7 添加SQLInsert 支持
ToDo:

***************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Reflection;
using MF.Core;
using System.Linq.Expressions;

namespace MF.Data.ORMapping
{

    public static class MFImproveReflect
    {
        private static Func<T, MethodInfo, object, object> GetSetDelegate<T>(MethodInfo m, Type type)
        {
            var param_obj = Expression.Parameter(typeof(T), "obj");
            var param_val = Expression.Parameter(typeof(object), "val");
            var param_m = Expression.Parameter(typeof(MethodInfo), "m");
            var body_val = Expression.Convert(param_val, type);
            var body = Expression.Call(param_obj, m, body_val);
            Action<T, MethodInfo, object> set = Expression.Lambda<Action<T, MethodInfo, object>>(body, param_obj, param_m, param_val).Compile();
            return (instance, method, v) =>
            {
                set(instance, method, v);
                return null;

            };
        }

        private static void FastSetValue<T>(this PropertyInfo property, T t, object value)
        {
            MethodInfo m = property.GetSetMethod();
            GetSetDelegate<T>(m, property.PropertyType)(t, m, value);
        }
    }

    public class MFReflect
    {
        


        public static bool SetProperty(Object instance,string name,object value)
        {
            try
            {
                PropertyInfo info = instance.GetType().GetProperty(name);
                if (info == null) return false;
                info.SetValue(instance, value, null);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static Type GetPropertyType(Object instance, string name)
        {
            try
            {
                PropertyInfo info = instance.GetType().GetProperty(name);
                if (info == null) return null;
                return info.PropertyType;
            }
            catch
            {
                return null;
            }
        }

        public static object GetProperty(Object instance, string name)
        {
            try
            {
                PropertyInfo info = instance.GetType().GetProperty(name);
                if (info == null) return null;
                return info.GetValue(instance,null);

            }
            catch
            {
                return null;
            }
        }

        public static bool IsHaveProperty(Object instance, string name)
        {
            try
            {
                PropertyInfo info = instance.GetType().GetProperty(name);
                return info != null;
            }
            catch
            {
                return false;
            }
        }


        public static Attribute GetClassAttribute(Type instance, Type type)
        {
            try
            {
                Attribute[] attrs = Attribute.GetCustomAttributes(instance);

                foreach (Attribute attr in attrs)
                {
                    if (attr.GetType()== type)
                    {
                        return attr;
                    }
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        public static List<string> GetPropertyList(Type instance)
        {
            List<string> list=new List<string>();
            try
            {
                PropertyInfo[] info = instance.GetType().GetProperties(BindingFlags.Public);
                foreach (PropertyInfo item in info)
                {
                    list.Add(item.Name);
                }
                return list;
            }
            catch
            {
                return list;
            }
        }

        public static Attribute GetPropertyAttribute(Type instance, Type type)
        {
            try
            {
                Attribute[] attrs = Attribute.GetCustomAttributes(instance);

                foreach (Attribute attr in attrs)
                {
                    if (attr.GetType() == type)
                    {
                        return attr;
                    }
                }
                return null;
            }
            catch
            {
                return null;
            }
        }
    }


    public class MFDataRelationAttInfo
    {
        public MFHasManyAttribute Master { get; set; }
        public string MasterPropertyName { get; set; }
        public MFBelongsToAttribute Detail { get; set; }
        public string DetailPropertyName { get; set; }
        public Boolean IsSuccess { get; set; }
        public Boolean Message { get; set; }

        public MFDataRelationAttInfo()
        {
            IsSuccess = false;
        }
    }

    public class MFDataClassSQLAttInfo
    {
        public string Where { get; set; }
        public string OrderBy { get; set; }
        public string SQL { get; set; }
        public string TableViewName { get; set; }
        public string TableName { get; set; }

    }

    public class MFDataTransfer
    {

        /// <summary>
        /// 根据Table返回对象集
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ADataTable"></param>
        /// <returns></returns>
        public static  List<T> GetList<T>(DataTable ADataTable)
        {

            List<T> Entities = new List<T>();
            foreach(DataRow row in ADataTable.Rows)
            {
                T Entity = Activator.CreateInstance<T>();
                SetEntity<T>(Entity, row);
                Entities.Add(Entity);
                
            }
            return Entities;
        }

        /// <summary>
        /// 根据一行设置一个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Entity"></param>
        /// <param name="ADataRow"></param>
        public static void  SetEntity<T>(T Entity, DataRow ADataRow)
        {
            Type type = typeof(T);
            foreach (DataColumn col in ADataRow.Table.Columns)
            {

                object value = ADataRow[col];
                string propertyName = GetRealPropertyName<T>(col.ColumnName);
                PropertyInfo pInfo = type.GetProperty(propertyName);
                if (pInfo != null)
                {
                    if (value is DBNull)
                        pInfo.SetValue(Entity, null, null);
                    else
                    {
                        
                        pInfo.SetValue(Entity, value, null);
                    }
                }
            }
        }


        public static List<string> GetPrimaryKeyFieldNames(Type dataType)
        {
            Type type = dataType;
            List<string> list = new List<string>();
            PropertyInfo[] infos = type.GetProperties();
            foreach (PropertyInfo info in infos)
            {
                Object[] attrs = info.GetCustomAttributes(false);

                foreach (var attr in attrs)
                {
                    if (attr.GetType() == typeof(MFFieldAttribute))
                    {
                        MFFieldAttribute field = (MFFieldAttribute)attr;
                        if (field.PrimaryKey)
                        {

                            list.Add(string.IsNullOrEmpty(field.FieldName) ? info.Name : field.FieldName);
                        }
                    }
                }
            }
            return list;
        }

        public static MFDataClassSQLAttInfo GetClassSQLInfo<T>()
        {
            Type type = typeof(T);

            MFDataClassSQLAttInfo rInfo = new MFDataClassSQLAttInfo();

            foreach (var attr in type.GetCustomAttributes(false))
            {
                if (attr.GetType() == typeof(MFTableAttribute))
                {
                    MFTableAttribute field = (MFTableAttribute)attr;

                    rInfo.Where = field.Where;
                    rInfo.OrderBy = field.OrderBy;
                    rInfo.SQL = field.SQL;
                    rInfo.TableViewName = field.TableName ?? type.Name;
                    rInfo.TableName = field.TableName ?? type.Name;
                    break;
                }

                if (attr.GetType() == typeof(MFViewAttribute))
                {
                    MFViewAttribute field = (MFViewAttribute)attr;
                    rInfo.Where = field.Where;
                    rInfo.OrderBy = field.OrderBy;
                    rInfo.SQL = field.SQL;
                    rInfo.TableViewName = field.ViewName ?? type.Name;
                    rInfo.TableName = field.TableName ?? type.Name;
                    break;
                }
            }
 

            return rInfo;
        }


        public static MFDataRelationAttInfo GetRelationInfo(Type instance, string relationName)
        {
            Type mType = instance;

            MFDataRelationAttInfo rInfo = new MFDataRelationAttInfo();

            PropertyInfo[] Infos = mType.GetProperties();
            foreach (PropertyInfo info in Infos)
            {
                Object[] attrs = info.GetCustomAttributes(false);
                MethodInfo method = info.GetGetMethod();


                foreach (var attr in attrs)
                {
                    if (attr.GetType() == typeof(MFHasManyAttribute))
                    {
                        MFHasManyAttribute field = (MFHasManyAttribute)attr;
                        if (MFString.ComparerNoCase(field.RelationName, relationName))
                        {
                            rInfo.Master = field;
                            rInfo.MasterPropertyName = info.Name;

                            break;
                        }
                    }
                }
                if (rInfo.Master != null) break;
            }

            if (rInfo.Master == null || rInfo.Master.DetailType == null) throw new Exception("Not found RelationName or DetailType is null");

            Type dType = rInfo.Master.DetailType;
            Infos = dType.GetProperties();

            foreach (PropertyInfo info in Infos)
            {
                Object[] attrs = info.GetCustomAttributes(false);

                foreach (var attr in attrs)
                {
                    if (attr.GetType() == typeof(MFBelongsToAttribute))
                    {
                        MFBelongsToAttribute field = (MFBelongsToAttribute)attr;
                        if (MFString.ComparerNoCase(field.RelationName, relationName))
                        {
                            rInfo.Detail = field;
                            rInfo.DetailPropertyName = info.Name;
                            break;
                        }
                    }
                }
                if (rInfo.Detail != null) break;
            }

            if (rInfo.Detail == null) throw new Exception("Not found RelationName");

            rInfo.IsSuccess = true;

            return rInfo;
        }

       

        public static List<string> GetPrimaryKeyFieldNames<T>()
        {
            Type type = typeof(T);
            List<string> list = new List<string>();
            PropertyInfo[] infos = type.GetProperties();
            foreach (PropertyInfo info in infos)
            {
                Object[] attrs = info.GetCustomAttributes(false);

                foreach (var attr in attrs)
                {
                    if (attr.GetType() == typeof(MFFieldAttribute))
                    {
                        MFFieldAttribute field = (MFFieldAttribute)attr;
                        if (field.PrimaryKey)
                        {

                            list.Add(string.IsNullOrEmpty(field.FieldName) ? info.Name : field.FieldName);
                        }
                    }
                }
            }
            return list;
        }

        public static string GetRealPropertyName<T>(string columnName)
        {
            Type type = typeof(T);
            PropertyInfo[] infos=type.GetProperties();
            foreach (PropertyInfo info in infos)
            {
                Object[] attrs = info.GetCustomAttributes(false);

                foreach (var attr in attrs)
                {
                    if (attr.GetType() == typeof(MFFieldAttribute))
                    {
                        MFFieldAttribute field = (MFFieldAttribute)attr;
                        if (MFString.ComparerNoCase(field.FieldName, columnName))
                        {
                            return info.Name;
                        }
                    }
                }
            }
            return columnName;
        }

        /// <summary>
        /// 根据对象集合返回DataSet
        /// </summary>
        /// <param name="AList"></param>
        /// <returns></returns>
        public static DataSet GetDataSet<T>(List<T> AList)
        {
            if (AList.Count == 0) return null;

            Type type = typeof(T);
            DataSet ds = new DataSet();
            T Entity=AList[0];
            SetDataSetScheme(ds, Entity);

            foreach (T AItem in AList)
            {
                DataRow ARow=ds.Tables[0].NewRow();

                foreach(DataColumn col in ARow.Table.Columns)
                {
                    string propertyName = GetRealPropertyName<T>(col.ColumnName);
                    PropertyInfo pInfo = type.GetProperty(propertyName);

                    object value = pInfo.GetValue(AItem, null);
                    if (value == null) value = DBNull.Value;
                    ARow[col.ColumnName] = value;

                }
                ds.Tables[0].Rows.Add(ARow);

            }
            ds.AcceptChanges();

            ds.EnforceConstraints = true;
            int i = 0;
            foreach (DataRow row in ds.Tables[0].Rows)
            {
                T item=AList[i];

                Object oState=MFReflect.GetProperty(item, "State");
                MFORMappingState ormState = MFORMappingState.Unchanged;
                if (oState != null) ormState = (MFORMappingState)oState;
                row.BeginEdit();
                switch (ormState)
                {
                    case MFORMappingState.Added: row.SetAdded(); break;
                    case MFORMappingState.Modified: row.SetModified(); break;
                    case MFORMappingState.Deleted: row.Delete(); break;

                }
                row.EndEdit();
                i++;
            }
            ds.EnforceConstraints = false;

            return ds;
        }

        /// <summary>
        /// 创建DataSet结构
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="ADataSet"></param>
        /// <param name="Entity"></param>

        public static void SetDataSetScheme<T>(DataSet ADataSet, T Entity)
        {
            Type type = typeof(T);
            
            string sTableName=type.Name;

            foreach(object AClassAtt  in type.GetCustomAttributes(false))
            {
                if (AClassAtt is MFTableAttribute)
                {
                    sTableName=(AClassAtt as MFTableAttribute).TableName;
                    break;
                }

                if (AClassAtt is MFViewAttribute)
                {
                    sTableName = (AClassAtt as MFViewAttribute).TableName;
                    break;
                }
            }

            DataTable tb=ADataSet.Tables.Add(sTableName);


            foreach(PropertyInfo pInfo in type.GetProperties())
            {

                Type pType=pInfo.PropertyType;
                bool bBreak = false;

                foreach (object APropertyAtt in pInfo.GetCustomAttributes(true))
                {
                    if (APropertyAtt is MFNotFieldAttribute)
                    {
                        bBreak = true; 
                        break;
                    }

                    if (APropertyAtt is MFFieldAttribute)
                    {
                        if (((MFFieldAttribute)APropertyAtt).Virtual)
                        {
                            bBreak = true;
                            break;
                        }
                    }

                }

                if (bBreak) continue;

                if (pType.IsGenericType && pType.GetGenericTypeDefinition() ==typeof(Nullable<>))
                {
                    pType = pType.GetGenericArguments()[0];
                }

                DataColumn col = tb.Columns.Add(pInfo.Name, pType);
               
                foreach(object APropertyAtt  in pInfo.GetCustomAttributes(false))
                {
                    if (APropertyAtt is MFFieldAttribute)
                    {
                        MFFieldAttribute AFieldAttribute = (MFFieldAttribute)APropertyAtt;
                        if (!string.IsNullOrEmpty(AFieldAttribute.FieldName))
                            col.ColumnName = AFieldAttribute.FieldName;

                        col.AllowDBNull = AFieldAttribute.AllowNull;

                        
                        if (AFieldAttribute.DataType != null)
                            col.DataType = AFieldAttribute.DataType;

                        if (AFieldAttribute.MaxLength != -1)
                            col.MaxLength = AFieldAttribute.MaxLength;
                    }
                }

           
            }

            Dictionary<string, string> keyList = GetKeyList(Entity);
            List<DataColumn> colList=new List<DataColumn>();
            foreach (var item in keyList)
            {
                colList.Add(tb.Columns[item.Key]);
            }

            tb.PrimaryKey = colList.ToArray();
        }


        public static Dictionary<string, string> GetKeyList<T>(T Entity)
        {
            Dictionary<string, string> keyList = new Dictionary<string, string>();
            PropertyInfo[] infos = Entity.GetType().GetProperties();
            foreach (PropertyInfo info in infos)
            {
                object[] attrs = info.GetCustomAttributes(false);
                foreach (var item in attrs)
                    if (item.GetType() == typeof(MFFieldAttribute))
                    {
                        MFFieldAttribute attr = (MFFieldAttribute)item;
                        if (attr.PrimaryKey)
                        {
                            string fieldName;
                            if (!string.IsNullOrEmpty(attr.FieldName))
                                fieldName = attr.FieldName;
                            else
                                fieldName = info.Name;

                            keyList.Add(fieldName, info.Name);
                        }

                    }

            }

            return keyList;
        }

        private static DbType GetRealColumnType(Type type)
        {
            if (type==typeof(Guid))
            {
                return DbType.Guid;
            }

            if (type == typeof(DateTime))
            {
                return DbType.DateTime;
            }

            if (type == typeof(int))
            {
                return DbType.Int32;
            }

            if (type == typeof(double))
            {
                return DbType.Double;
            }

            if (type == typeof(decimal))
            {
                return DbType.Decimal;
            }

            if (type == typeof(bool))
            {
                return DbType.Byte;
            }

            if (type == typeof(byte[]))
            {
                return DbType.Binary;
            }

            return DbType.String;
        }
    }


    public class MFSQLColumn 
    {
        public MFSQLColumn(string name)
        {
            Name = name;
            PrimaryKey = false;
        }

        public MFSQLColumn(string name, bool primaryKey)
            : this(name)
        {
            PrimaryKey = primaryKey;
        }


        public MFSQLColumn(string name, string alias)
            : this(name)
        {
            Alias = alias;
        }

        public string Name { get; set; }
        public string Alias { get; set; }
        public object Value { get; set; }
        public string Function { get; set; }
        public bool  PrimaryKey { get; set; }
        public MFSQLOrder Order { get; set; }
    }

    public class MFSQLColumns : List<MFSQLColumn>
    {
        public void Add(string columnName)
        {
            this.Add(new MFSQLColumn(columnName));
        }

        public MFSQLColumn FindColumn(string columnName)
        {
            foreach (var item in this)
            {
                if (MFString.ComparerNoCase(columnName, item.Name))
                {
                    return item;
                }
            }
            return null;
        }

        public MFSQLColumn this[string columnName] 
        {
            get { return FindColumn(columnName); }
            set 
            { 
                MFSQLColumn col= FindColumn(columnName);
                if (col != null)
                {
                    col = value;
                }
                else
                {
                    MFThrowHelper.ThrowArgumentException();
                }
            }
        }
    }

    public enum MFSQLParentheses {None,Left,Right}
    public enum MFSQLOperate { More, Less, Equal, MoreEqual, LessEqual,Not,Is,In,Like }
    public enum MFSQLLink { None, And, Or, Between }
    public enum MFSQLOrder {ASC,DESC }

    public class MFSQLWhere
    {
        public MFSQLWhere(string name)
        {
            Name = name;
            Operate = MFSQLOperate.Equal;
            Link = MFSQLLink.And;
        }

        public MFSQLWhere(string name, MFSQLOperate operate,MFSQLLink link,Object value)
            : this(name, operate)
        {
            Value = value;
        }

        public MFSQLWhere(string name, MFSQLOperate operate)
            : this(name)
        {
            Operate = operate;
        }


        public MFSQLWhere(string name, MFSQLOperate operate,MFSQLLink link)
            : this(name, operate)
        {
            Link = link;
        }

        public MFSQLWhere(string name, object value)
            :this(name)
        {
            Value = value;
        }

        public string Name { get; set; }
        public object Value { get; set; }
        public MFSQLLink Link { get; set; }
        public MFSQLOperate Operate { get; set; }
        public MFSQLParentheses Parentheses { get; set; }
        public string Function { get; set; }
        public string SQL { get; set; }
    }

    public class MFSQLWheres : List<MFSQLWhere>
    {
        public void Add(string whereName)
        {
            this.Add(new MFSQLWhere(whereName));
        }

        public void Add(string whereName, Object value)
        {
            this.Add(new MFSQLWhere(whereName, value));
        }

        public void Add(string whereName, MFSQLOperate operate, MFSQLLink link, Object value)
        {
            this.Add(new MFSQLWhere(whereName, operate, link,value));
        }

        public void Add(string whereName, MFSQLOperate operate, MFSQLLink link)
        {
            this.Add(new MFSQLWhere(whereName, operate, link));
        }

        public MFSQLWhere FindColumn(string whereName)
        {
            foreach (var item in this)
            {
                if (MFString.ComparerNoCase(whereName, item.Name))
                {
                    return item;
                }
            }
            return null;
        }

        public MFSQLWhere this[string whereName]
        {
            get { return FindColumn(whereName); }
            set
            {
                MFSQLWhere col = FindColumn(whereName);
                if (col != null)
                {
                    col = value;
                }
                else
                {
                    MFThrowHelper.ThrowArgumentException();
                }
            }
        }
    }



    public class MFSQLBase
    {
        public const string cWhere = " Where ";
        public const string cOrderBy = " Order By ";
        public const string cSelect = " Select ";
        public const string cAsterisk = " * ";
        public const string cDesc = " DESC ";

        public const string cAsc = " ASC ";
        public const string cAs = " AS ";
        public const string cDelete = " Delete ";
        public const string cUpdate = " Update ";
        public const string cSet = " Set ";
        public const string cAnd = " And ";
        public const string cOr = " Or ";
        public const string cNot = " Not ";

        public const string cDistinct = " DISTINCT ";
        public const string cGroupBy = " GROUP BY ";
        public const string cHaving = " HAVING ";
        public const string cUnion = " UNION ";
        public const string cAll = " ALL ";
        public const string cWith = " WITH ";
        public const string cInto = " INTO ";
        public const string cAVG = " AVG ";
        public const string cCast = " Cast";
        public const string cCount = " COUNT";
        public const string cMax = " MAX";
        public const string cMin = " MIN";
        public const string cSum = " SUM";
        public const string cValues = " VALUES";

        public const string cEqual = "=";
        public const string cVirgule = "/";
        public const string cLess = "<";
        public const string cMore = ">";
        public const string cQuotation = "\"";
        public const string cSpace = " ";
        public const string cComma = ",";

        public MFSQLBase()
        {

            ParameterKey = "@";
        }

        public static string ParameterKey { get; set; }
        
        public static string GetColumnString(MFSQLColumns colum)
        {
            string columnString = string.Empty;

            foreach (var item in colum)
            {
                string str = string.Empty;
                if (!string.IsNullOrEmpty(item.Function))
                {
                    str = string.Format(item.Function, item.Name);
                }
                else
                {
                    str = item.Name;
                }

                if (!string.IsNullOrEmpty(item.Alias)) str = string.Format("{0} As {1}", str, item.Alias);


                if (colum.IndexOf(item) != (colum.Count - 1))
                    columnString += str + ",";
                else
                    columnString += str;

            }
            return columnString;
        }

        public static string GetWhereString(MFSQLWheres where)
        {
            string whereString = string.Empty;

            foreach (var item in where)
            {
                string str = string.Empty;

                if (!string.IsNullOrEmpty(item.Function))
                {
                    str = string.Format(item.Function, item.Name);
                }
                else
                {
                    str = item.Name;
                }


                switch (item.Operate)
                {
                    case MFSQLOperate.Equal: str = str + "="; break;
                    case MFSQLOperate.Less: str = str + "<"; break;
                    case MFSQLOperate.More: str = str + ">"; break;
                    case MFSQLOperate.LessEqual: str = str + "<="; break;
                    case MFSQLOperate.MoreEqual: str = str + ">="; break;
                    case MFSQLOperate.In: str = str + " in "; break;
                    case MFSQLOperate.Is: str = str + " is "; break;
                    case MFSQLOperate.Not: str = str + " not "; break;
                    case MFSQLOperate.Like: str = str + " like "; break;
                }

                if (item.Value != null)
                {
                    if (item.Value.GetType() == typeof(String))
                        str = str + string.Format("'{0}'", item.Value);
                    else
                        str = str + item.Value;
                }
                else
                    str = str + ParameterKey + item.Name;

                switch (item.Parentheses)
                {
                    case MFSQLParentheses.Left: str = string.Format("({0}", str); break;
                    case MFSQLParentheses.Right: str = string.Format("{0})", str); break;
                    case MFSQLParentheses.None: str = string.Format("{0}", str); break;
                }

                if (!string.IsNullOrEmpty(whereString))
                    switch (item.Link)
                    {
                        case MFSQLLink.And: ; str = " And " + str; break;
                        case MFSQLLink.Or: ; str = " Or " + str; break;
                        case MFSQLLink.Between: ; break;
                    }

                //if (string.IsNullOrEmpty(whereString)
                whereString += str;

            }

            if (!string.IsNullOrEmpty(whereString)) whereString = "Where " + whereString;
            return whereString;
        }

        public static string Replace(string strValue, string replaceValue, object[] args)
        {
            int i = 0;
            int j = 0;
            string strResult = string.Empty;
            while (i < strValue.Length)
            {
                if (replaceValue.Length <= (strValue.Length - i))
                {
                    string str = strValue.Substring(i, replaceValue.Length);
                    if (replaceValue == str)
                    {
                        strResult += args[j].ToString();
                        i += replaceValue.Length;
                        j++;
                        continue;
                    }

                }
                strResult += strValue[i];
                i++;
            }

            return strResult;
        }

        public virtual void Clear()
        {

        }

        public virtual string CreateSQL()
        {
            return string.Empty;
        }

        /// <summary>
        /// ?
        /// </summary>
        /// <param name="sqlString"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        public static string GetStaticSQL(string sqlString, params object[] args)
        {
            int i = 0;
            if (args == null) return sqlString;

            foreach (object item in args)
            {
                if (item.GetType() == typeof(String) || item.GetType() == typeof(DateTime) || item.GetType() == typeof(Guid))
                {
                    args[i] = string.Format("'{0}'", item);
                }

                //sqlString = sqlString.Replace("{" + i.ToString() + "}", args[i].ToString());

                i++;
            }

            sqlString = MFSQLBase.Replace(sqlString, "?", args);
            return sqlString;
        }


    }


    public class MFSQLUpdate : MFSQLBase
    {
        public const string cUpdate = "Update {0} SET {1} {2} ";

        public MFSQLUpdate()
        {
            Wheres = new MFSQLWheres();
            
        }

        public string TableName { get; set; }

        public MFSQLWheres Wheres { get; set; }

        public MFSQLColumns Columns { get; set; }

        

        public override void Clear()
        {

            Wheres.Clear();

        }

        public string GetUpdateSQL()
        {
            string sFields = string.Empty;

            foreach (MFSQLColumn col in Columns)
            {
                string str = String.Empty;
                if (col.Value != null)
                {
                    if (col.Value.GetType() == typeof(String))
                        str = string.Format("'{0}'", col.Value);
                    else
                        str = col.Value.ToString();
                }
                else
                    str = ParameterKey + col.Name;

                if (!string.IsNullOrEmpty(sFields)) sFields += " , ";
                sFields += string.Format("{0} = {1}", col.Name, str);
            }

            return sFields;

        }

        public override string CreateSQL()
        {

            string sWhere = MFSQLBase.GetWhereString(Wheres);

            return string.Format(cUpdate, TableName,GetUpdateSQL(), sWhere);
        }
    }

    public class MFSQLDelete : MFSQLBase
    {
        public const string cDelete = "Delete From {0} {1} ";
        public const string cDeleteSimple = "Delete  From {0} ";
        public MFSQLDelete()
        {
            Wheres = new MFSQLWheres();
            
        }

        public string TableName { get; set; }

        public MFSQLWheres Wheres { get; set; }

        public override void Clear()
        {

            Wheres.Clear();

        }

        public override string CreateSQL()
        {

            string sWhere = MFSQLBase.GetWhereString(Wheres);

            return string.Format(cDelete, TableName, sWhere);
        }

    }

    public class MFSQLInsert : MFSQLBase
    {
        public const string cInsert = "Insert INTO {0}({1}) Values({2}) ";

        public MFSQLInsert()
        {
            Wheres = new MFSQLWheres();
            
        }

        public string TableName { get; set; }

        public MFSQLWheres Wheres { get; set; }

        public MFSQLColumns Columns { get; set; }


        public override void Clear()
        {

            Wheres.Clear();

        }

        public string GetInsertSQL(bool isField)
        {
            string sFields = string.Empty;
            string sValue = string.Empty;
            foreach (MFSQLColumn col in Columns)
            {
                if (!string.IsNullOrEmpty(sFields)) sFields += " , ";
                sFields += col.Name;

                string str = String.Empty;
                if (col.Value != null)
                {
                    if (col.Value.GetType() == typeof(String))
                        str = string.Format("'{0}'", col.Value);
                    else
                        str = col.Value.ToString();
                }
                else
                    str = ParameterKey + col.Name;

                if (!string.IsNullOrEmpty(sValue)) sValue += " , ";
                sValue += str;
            }

            if (isField)
                return sFields;
            else
                return sValue;
        }

        public override string CreateSQL()
        {

            return string.Format(cInsert, TableName, GetInsertSQL(true), GetInsertSQL(false));
        }
    }


    public class MFSQLSelect : MFSQLBase
    {
        public const string cSelectSimple = "Select * From {0} ";
        public const string cSelectColumn = "Select {0} From {1} ";
        public const string cSelect = "Select {0} From {1} {2} ";

        public MFSQLColumns Column { get; set; }
        public MFSQLColumns OrderBy { get; set; }
        public MFSQLColumns GroupBy { get; set; }
        public MFSQLWheres Where { get; set; }
        private string WhereString;

        public string Top { get; set; }
        public string TableName { get; set; }

        public MFSQLSelect()
        {
            Column = new MFSQLColumns();
            OrderBy = new MFSQLColumns();
            GroupBy = new MFSQLColumns();
            Where = new MFSQLWheres();
            
        }

        public static string GetSQLWhereCondition(string whereFirst,string whereSecond)
        {
 
            if (string.IsNullOrEmpty(whereFirst))
            {
                if (string.IsNullOrEmpty(whereSecond))
                    return string.Empty;
                else
                    return MFSQLBase.cWhere + whereSecond;
                
            }
            else
            {
                if (string.IsNullOrEmpty(whereSecond))
                    return MFSQLBase.cWhere + whereFirst;
                else
                    return MFSQLBase.cWhere + whereFirst + MFSQLBase.cAnd + whereSecond;
            }

        }

        public static string GetSQLOrderByCondition(string orderByFirst,string orderBySecond)
        {
            if (string.IsNullOrEmpty(orderByFirst))
            {
                if (string.IsNullOrEmpty(orderBySecond))
                    return string.Empty;
                else
                    return MFSQLBase.cOrderBy + orderBySecond;

            }
            else
            {
                if (string.IsNullOrEmpty(orderBySecond))
                    return MFSQLBase.cOrderBy + orderByFirst;
                else
                    return MFSQLBase.cOrderBy + orderByFirst + MFSQLBase.cComma + orderBySecond;
            }
        }

        public static string GetSQLSelect(string sqlString, params object[] args)
        {

            return MFSQLBase.GetStaticSQL(sqlString, args);
        }

        public override void Clear()
        {
            Column.Clear();
            Where.Clear();
            Top = string.Empty;
            WhereString = string.Empty;

        }

        public override string CreateSQL()
        {
            string sTop=string.Empty;

            if (!string.IsNullOrEmpty(Top)) sTop =string.Format("Top {0} ", Top);

            string sCol = MFSQLBase.GetColumnString(Column);
            string sWhere = MFSQLBase.GetWhereString(Where);
            

            return string.Format(cSelect,sTop+sCol,TableName,sWhere);
        }
    }

    public enum MFExceptionArgument
    {
        obj,
        dictionary,
        dictionaryCreationThreshold,
        array,
        info,
        key,
        collection,
        list,
        match,
        converter,
        queue,
        stack,
        capacity,
        index,
        startIndex,
        value,
        count,
        arrayIndex,
        name,
        mode
    }

    public class MFThrowHelper
    {
        public static string GetArgumentName(MFExceptionArgument argument)
        {
            switch (argument)
            {
                case MFExceptionArgument.obj:
                    return "obj";

                case MFExceptionArgument.dictionary:
                    return "dictionary";

                case MFExceptionArgument.dictionaryCreationThreshold:
                    return "dictionaryCreationThreshold";

                case MFExceptionArgument.array:
                    return "array";

                case MFExceptionArgument.info:
                    return "info";

                case MFExceptionArgument.key:
                    return "key";

                case MFExceptionArgument.collection:
                    return "collection";

                case MFExceptionArgument.list:
                    return "list";

                case MFExceptionArgument.match:
                    return "match";

                case MFExceptionArgument.converter:
                    return "converter";

                case MFExceptionArgument.queue:
                    return "queue";

                case MFExceptionArgument.stack:
                    return "stack";

                case MFExceptionArgument.capacity:
                    return "capacity";

                case MFExceptionArgument.index:
                    return "index";

                case MFExceptionArgument.startIndex:
                    return "startIndex";

                case MFExceptionArgument.value:
                    return "value";

                case MFExceptionArgument.count:
                    return "count";

                case MFExceptionArgument.arrayIndex:
                    return "arrayIndex";

                case MFExceptionArgument.name:
                    return "name";

                case MFExceptionArgument.mode:
                    return "mode";
            }
            return string.Empty;
        }


        public static void ThrowArgumentException()
        {
            throw new ArgumentOutOfRangeException(GetArgumentName(MFExceptionArgument.name),
                MFResource.ResourceManager.GetString(GetArgumentName(MFExceptionArgument.name)));
        }

    }

    /// <summary>
    /// 表对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class MFTableAttribute : Attribute
    {

        public string TableName { get; set; }
        public string Where { get; set; }
        public string OrderBy { get; set; }
        public string SQL { get; set; }
		public MFTableAttribute() { }

		public MFTableAttribute(string tableName)
		{
            TableName = tableName;
		}
    }


    /// <summary>
    /// 非字段对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFNotFieldAttribute : Attribute
    {
       
    }

    /// <summary>
    /// 字段对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
	public class MFFieldAttribute : Attribute
	{
		public string FieldName { get; set; }
		public object DefaultValue { get; set; }
        public bool PrimaryKey { get; set; }
        public bool AllowNull { get; set; }
        public bool DbGenerated { get; set; }
        public bool ReadOnly { get; set; }
        public Type DataType { get; set; }
        public int MaxLength { get; set; }
        public bool Virtual { get; set; }
        public String Formula { get; set; }
        public String UniqueKey { get; set; }
        public String SqlType { get; set; }
        public bool Unique { get; set; }
        public bool Update { get; set; }
        public bool Insert { get; set; }

		public bool IsChangeable()
		{
			if (PrimaryKey || DbGenerated)
			{
				return false;
			}
            return ReadOnly;
		}

        public MFFieldAttribute()
		{
			PrimaryKey = false;
			AllowNull = false;
			DbGenerated = false;
			ReadOnly = true;
            MaxLength = -1;
            DataType = null;
            Virtual = false;
            Update = true;
            Insert = true;
		}

        public MFFieldAttribute(string fieldName):this()
        {
            FieldName = fieldName;
        }
	}

    /// <summary>
    /// 自定义对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFNestedAttribute : Attribute
    {
        public bool Update { get; set; }
        public bool Insert { get; set; }
        public Type MapType { get; set; }
        public String ColumnPrefix { get; set; }

        public MFNestedAttribute(Type mapType)
        {
            MapType = mapType;
            Update = true;
            Insert = true;
        }
    }

    /// <summary>
    /// 视图对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class MFViewAttribute : Attribute
    {
        public string TableName { get; set; }
        public string ViewName { get; set; }
        public string Where { get; set; }
        public string OrderBy { get; set; }
        public string SQL { get; set; }
        public MFViewAttribute() { }

        public MFViewAttribute(string viewName)
        {
            ViewName = viewName;
        }
    }


    /// <summary>
    /// 一对一属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFOneToOneAttribute : Attribute
    {
        public MFCascade Cascade { get; set; }
        public MFFetch Fetch { get; set; }
        
        public Type MapType { get; set; }
        public bool Constrained { get; set; }

        public string SelfColumnKey { get; set; }
        public string OutColumnKey { get; set; }
        public bool Update { get; set; }
        public bool Insert { get; set; }

        public bool Inverse { get; set; }
        public bool Lazy { get; set; }

        public MFOneToOneAttribute(Type type)
        {
            MapType = type;
            Update = false;
            Insert = false;
        }
    }

    /// <summary>
    /// 多表关联对象HasMany属性类  RelationName DetailColumnKey 不像NHibernate那样复杂，简单化是主要目的
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFHasManyAttribute : Attribute
    {
        public string RelationName { get; set; }
        public string DetailColumnKey { get; set; }

        public Type DetailType { get; set; }
        public string Where { get; set; }
        public string OrderBy { get; set; }

        public bool Inverse { get; set; }
        public bool Lazy { get; set; }
        public MFCascade Cascade { get; set; }

        public bool Update { get; set; }
        public bool Insert { get; set; }

        public MFHasManyAttribute(Type detailType, string relationName, string detailColumnKey)
        {
            RelationName = relationName;
            DetailColumnKey = detailColumnKey;
            DetailType = detailType;
            Cascade=MFCascade.All;
        }
    }

    public enum MFCascade{None,All,SaveUpdate,Delete,AllDeleteOrphan};
    public enum MFFetch { Unspecified, Join, Select, SubSelect };

    /// <summary>
    /// 多表关联对象BelongsTo属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFBelongsToAttribute : Attribute
    {
        public string RelationName { get; set; }
        public string MasterColumnKey { get; set; }

        public bool NotNull { get; set; }
        public Type MasterType { get; set; }

        public MFBelongsToAttribute(Type masterType, string relationName, String masterColumnKey)
        {
            MasterColumnKey = masterColumnKey;
            RelationName = relationName;
            MasterType=masterType;

        }
    }


    /// <summary>
    /// 存储过程对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
    public class MFStoredAttribute : Attribute
    {

        public string StoredProcedureName { get; set; }
        public string Describe { get; set; }
        public MFStoredAttribute() { }

        public MFStoredAttribute(string storedProcedureName)
        {
            StoredProcedureName = storedProcedureName;
        }
    }

    /// <summary>
    /// 存储过程参数对象属性类
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class MFStoredParameterAttribute : Attribute
    {
        public MFStoredParameterAttribute()
        {
            Size = 50;
            Direction = ParameterDirection.Input;
            DbType = DbType.String;

        }
        public DbType DbType { get; set; }
        public int Size { get; set; }
        public ParameterDirection Direction { get; set; }
        public bool IsNullable { get; set; }
        public string ParameterName { get; set; }
        public string SourceColumn { get; set; }
        public DataRowVersion SourceVersion { get; set; }
    }
    
}
